<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>TreeSelector Demo for dojo 1.4</title>

<link rel="stylesheet" type="text/css" href="../theme-remote.css" />
<style type="text/css">
body {
    font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;
    font-size: 11px;
}

#debugPanel pre {
    font-family: "Lucida Console", "Courier New", Courier, monospace;
}

div.container {
    border: 0px solid green;
    margin: 10px;
}
</style>

<script type="text/javascript">
var djConfig = {
    isDebug: true,
    parseOnLoad: true,
    locale: "zh",
    extraLocale: ["en"],
    baseUrl: "../script/dojo-1.4.3/dojo/",
    modulePaths: {
        "demo": "../../../script/demo",
        "com": "../../../script/com"
    }
};
</script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/dojo/1.4.3/dojo/dojo.xd.js.uncompressed.js"></script>
<script type="text/javascript" src="../script/dojo-require.js"></script>
<script type="text/javascript">
    dojo.require("dijit.tree.ForestStoreModel");
    dojo.require("dijit.tree.TreeStoreModel");
    dojo.require("dijit.Tree");

    dojo.require("demo.widget.TreeSelector");
</script>
<script type="text/javascript" src="../script/utils.js"></script>
<script type="text/javascript">
function debug(messages) {
    var msg = demo.utils._getDebugMsg.apply(null, arguments);
    console.debug(msg);

    var msgDiv = dojo.byId("debugPanelContent");
    msgDiv.innerHTML = msg;
}

function append(messages) {
    var msg = demo.utils._getDebugMsg.apply(null, arguments);

    var msgDiv = dojo.byId("debugPanelContent");
    msgDiv.innerHTML += "\n" + msg;
}

function show(id) {
    demo.utils.show(id);
}

function hide(id) {
    demo.utils.hide(id);
}
</script>
<style type="text/css">
@import "../css/rounded-button.css";
@import "../css/rounded-corners.css";

body {
    padding: 10px;
}

/* TreeSelector popup menu style */
.TreeSelectorPopUp {
    /*border: 1px solid black;*/
    background-color: #F7F7F7;
    min-width: 100px;
    min-height: 50px;
    max-width: 400px;
    max-height: 400px;
    overflow: auto;
}

/* Selected tree node label style */
.tundra .dijitTreeNodeSelected .dijitTreeLabel {
    background-color: #3559ac;
    color: white;
}

/* Owner group tree node icon style */
.OwnerGroupIcon {
    background: url("../images/icons/group.gif") scroll 0 0 no-repeat;
}

/* Product tree node icon style */
.ProductIcon {
    background: url("../images/icons/prodtree.gif") scroll 0 0 no-repeat;
}

/* Product group opened tree node icon style */
.FolderOpenedIcon {
    background: url("../images/icons/folder_o.gif") scroll 0 0 no-repeat;
}

/* Product group closed tree node icon style */
.FolderClosedIcon {
    background: url("../images/icons/folder_c.gif") scroll 0 0 no-repeat;
}

/* Owner group tree node label style */
.OwnerGroupLabel {
    font-weight: bold;
    font-style: italic;
}

.tundra .dijitTreeNodeHover {
    /*background-image: none;
    background-color: #3559ac;
    color: white;*/
}

/* icon class for ArrowUp button */
.iconArrowUp {
    background-image: url("../images/icons/blue_up.png");
    background-repeat: no-repeat;
    width: 15px;
    height: 17px;
    text-align: center;
}

/* icon class for ArrowDown button */
.iconArrowDown {
    background-image: url("../images/icons/blue_down.png");
    background-repeat: no-repeat;
    width: 15px;
    height: 17px;
    text-align: center;
}

/* icon class for disabled ArrowUp button */
.dijitDisabled .iconArrowUp {
    opacity: 0.4;
    filter: alpha(opacity=40); /* IE opacity */
}

/* icon class for disabled ArrowDown button */
.dijitDisabled .iconArrowDown {
    opacity: 0.4;
    filter: alpha(opacity=40); /* IE opacity */
}

/* remove the little black down arrow on the dropdown ArrowDown button */
.tundra #arrowDownButton .dijitArrowButtonInner {
    background: none;
    width: 0;
    height: 0;
}

/* remove the little black down arrow on the dropdown ArrowUp button */
.tundra #arrowUpButton .dijitArrowButtonInner {
    background: none;
    width: 0;
    height: 0;
}

/* link button */
.linkButton .dijitButtonNode {
    border: none;
    background-image: none;
    background-color: transparent;
}

/* link button text */
.linkButton .dijitButtonText {
    color: blue;
    text-decoration: underline;
}

/* link button text hover effect */
.linkButtonHover .dijitButtonText {
    color: #6699CC;
    text-decoration: underline;
}

/* link button text disabled effect */
.linkButtonDisabled .dijitButtonText {
    text-decoration: none;
}

/* add favorite icon */
.linkButton .addFavIcon {
    background-image: url("../images/icon-link-add-dark.gif");
    background-repeat: no-repeat;
    width: 13px;
    height: 13px;
    text-align: center;
}

/* add favorite disabled icon */
.linkButtonDisabled .addFavIcon {
    background-image: url("../images/icon-link-add-dark-disabled.gif");
}
</style>
<script type="text/javascript">
var GlobalVariables = {
    "contextURL": null,
    "dataPath": "../data",
    "identifier": "moniker",
    "TreeSelectorQueries": {
        "all": {top : true},
        "dsp": {dsp : true},
        "fav": {fav : true}
    },
    "FormParams": {
        "productGroupCategory": "set:$page.productGroupCategory",
        "productGroup": "set:$page.productGroup",
        "product": "set:$page.product"
    },
    "DefaultOptions": {
        "productGroupCategory": null,
        "productGroup": null,
        "product": null
    }
};

function decodeURL(str) {
    return unescape(str.replace(/\+/g, " "));
}

function parseURL() {
    var url = dojo.doc.URL;
    console.debug(url);
    var parts = url.split("?");
    GlobalVariables.contextURL = parts[0];
    var contextURL = GlobalVariables.contextURL;
    dojo.attr(dojo.byId("form1"), "action", contextURL);

    var queryStr = parts[1];
    if (!queryStr)  {
        return;
    }

    var params = queryStr.split("&");
    for (var i in params) {
        var param = params[i];
        var entry = param.split("=");
        var key = decodeURL(entry[0]);
        var value = entry[1];
        switch (key) {
            case GlobalVariables.FormParams["productGroupCategory"]:
                GlobalVariables.DefaultOptions["productGroupCategory"] = value;
                break;
            case GlobalVariables.FormParams["productGroup"]:
                GlobalVariables.DefaultOptions["productGroup"] = value;
                break;
            case GlobalVariables.FormParams["product"]:
                GlobalVariables.DefaultOptions["product"] = value;
                break;
        }
    }
    console.debug("DefaultOptions", GlobalVariables.DefaultOptions);
}

demo.selector = {};

// remember if selector has been included in page notifier
demo.selector.includedInPageNotifier = {
    "productGroupCategorySelector": false,
    "productGroupSelector": false,
    "productSelector": false
};

demo.selector.settings = {
    "productGroupCategorySelector": {
        ready: false
    },
    "productGroupSelector": {
        ready: false
    },
    "productSelector": {
        ready: false,
        defaultItem: {
            moniker: "all",
            name: "-- All --",
            type: "product",
            top: true
        }
    }
};

//////////////////////////////
dojo.ready(function() {
    dojo.byId('version').innerHTML = 'Version ' + dojo.version;

    debug('loaded');

    parseURL();
    init();
    load();

    // subscribe when product list json data loaded
    dojo.subscribe("productSelector-data-loaded", function(productStoreData) {
        var productSelector = dijit.byId("productSelector");

        var defaultItem = demo.selector.settings["productSelector"].defaultItem;
        if (defaultItem) {
            productStoreData.items.unshift(defaultItem);
        }

        // create a new data store for product selector
        var productStore = new dojo.data.ItemFileWriteStore({
            data: productStoreData
        });

        demo.selector.changeStoreForSelector(productSelector, productStore);
        productSelector.attr("identity", "all");

        // select default product
        var defaultProduct = GlobalVariables.DefaultOptions["product"];
        if (defaultProduct) {
            productSelector.attr("identity", defaultProduct);
            delete GlobalVariables.DefaultOptions["product"]; // clear default product
        } else {
            // expand tree if
        }
    });
});

dojo.addOnLoad(function() {
    // bind events for productGroupCategorySelector
    dojo.connect(dijit.byId("productGroupCategorySelector"), "onChange", function(value) {
        updateAddToFavoritesStatus();
    });

    // bind events for productGroupSelector
    dojo.connect(dijit.byId("productGroupSelector"), "onChange", function(value) {
        updateAddToFavoritesStatus();
    });
});

//////////////////////////////
/**
 * Initiates widgets for product group navigation.
 */
function init() {
    initProductGroupCategorySelector();
    initProductGroupSelector();
    initProductSelector();
}

/**
 * Loads the large data set of product groups.
 */
function load() {
    console.debug('smd.ppg.load');

    // Add a root item to product group data store, as the default root in product group navigation popup tree.
    var rootItem = {moniker: '$root$', name: 'ROOT', search: false};
    var productGroupSelector = dijit.byId('productGroupSelector');
    productGroupSelector.store.newItem(rootItem); // this triggers data store to load all its data.

    // show loading overlay for product group category selector
    showProductGroupCategorySelectorOverlay();

    // show loading overlay for product group selector
    showProductGroupSelectorOverlay();

    // init items in product group category selector
    var deferred = initProductGroupCategorySelectorItems();
    deferred.addCallback(function() {
        // update items in product group category selector
        updateProductGroupCategorySelector(resetProductGroupCategorySelector);

        initProductGroupNavigation();

        // bind event handlers
        bindEvents();
    });
}

/**
 * Binds the events for selectors.
 */
function bindEvents() {
    // connect event handlers
    dojo.connect(dijit.byId('productGroupCategorySelector'), 'onChange', onchangeProductGroupCategorySelector);
    dojo.connect(dijit.byId('productGroupSelector'), 'onChange', onchangeProductGroupSelector);
    dojo.connect(dijit.byId('productSelector'), 'onChange', onchangeProductSelector);
}

/**
 * Initiates widgets for product group category selector.
 */
function initProductGroupCategorySelector() {
    console.debug('[init]', 'productGroupCategorySelector');

    var productGroupCategoryStore = new dojo.data.ItemFileWriteStore({url: GlobalVariables.dataPath + '/product_group_categories.json'});

    // product group category selector
    var productGroupCategorySelector = new dijit.form.ComboBox({
        id: 'productGroupCategorySelector',
        //name: 'set:$page.productGroupCategory',
        value: '-- All --',
        store: productGroupCategoryStore,
        searchAttr: 'name',
        query: {show: true},
        style: 'width: 200px;'
    }, 'productGroupCategorySelector');

    // loading overlay for product group category selector
    var productGroupCategorySelectorOverlay = new dojox.widget.Standby({
        id: 'productGroupCategorySelectorOverlay',
        target: 'productGroupCategorySelector',
        color: '#FFFFE0',
        centerIndicator: 'text',
        text: 'Loading...'
    });
    //document.body.appendChild(productGroupCategorySelectorOverlay.domNode);
    dojo.place(productGroupCategorySelectorOverlay.domNode, dojo.byId('productGroupCategoryHidden'), 'after');
    productGroupCategorySelectorOverlay.startup();
}

/**
 * Initiates widgets for product group selector.
 */
function initProductGroupSelector() {
    console.debug('[init]', 'productGroupSelector');

    var productGroupStore = new dojo.data.ItemFileWriteStore({url: GlobalVariables.dataPath + "/product_groups.json"});

    // product group selector
    var productGroupSelector = new demo.widget.TreeSelector({
        id: 'productGroupSelector',
        //name: 'set:$page.productGroup',
        value: '-- Select a product group --',
        store: productGroupStore,
        searchAttr: 'name',
        query: GlobalVariables.TreeSelectorQueries['all'],
        invalidQuery: {type: 'owner'},
        queryExpr: '*${0}*',
        highlightMatch: 'all', // One of: 'first', 'all' or 'none'.
        autoComplete: false,
        disabled: true,
        iconClasses: {
            'opened': 'FolderOpenedIcon',
            'closed': 'FolderClosedIcon',
            'leaf': 'FolderClosedIcon',
            'nonSelectableOpened': 'OwnerGroupIcon',
            'nonSelectableClosed': 'OwnerGroupIcon'
        },
        nonSelectableLabelClass: 'OwnerGroupLabel',
        style: 'width: 200px;'
    }, 'productGroupSelector');

    initValidation(productGroupSelector, 'productGroupHidden');

    // loading overlay for product group selector
    var productGroupSelectorOverlay = new dojox.widget.Standby({
        id: 'productGroupSelectorOverlay',
        target: 'productGroupSelector',
        color: '#FFFFE0',
        centerIndicator: 'text',
        text: 'Loading...'
    });
    //document.body.appendChild(productGroupSelectorOverlay.domNode);
    dojo.place(productGroupSelectorOverlay.domNode, dojo.byId('productGroupHidden'), 'after');
    productGroupSelectorOverlay.startup();
}

/**
 * Initiates widgets for product selector.
 */
function initProductSelector() {
    console.debug('[init]', 'productSelector');

    // product selector
    var productSelector = new demo.widget.TreeSelector({
        id: 'productSelector',
        //name: 'set:$page.product',
        value: demo.selector.settings['productSelector'].defaultText || '-- Select a product --',
        store: null,
        searchAttr: 'name',
        query: GlobalVariables.TreeSelectorQueries['all'],
        invalidQuery: {type: 'owner'},
        queryExpr: '*${0}*',
        highlightMatch: 'all', // One of: 'first', 'all' or 'none'.
        autoComplete: false,
        disabled: true,
        iconClasses: {
            'opened': null,
            'closed': null,
            'leaf': 'ProductIcon',
            'nonSelectableOpened': 'OwnerGroupIcon',
            'nonSelectableClosed': 'OwnerGroupIcon'
        },
        nonSelectableLabelClass: 'OwnerGroupLabel',
        style: 'width: 200px;'
    }, 'productSelector');
    productSelector.attr('disabled', false);
    //productSelector.attr('identity', smd.CLEAR_VALUE);

    initValidation(productSelector, 'productHidden');

    // loading overlay for product selector
    var productSelectorOverlay = new dojox.widget.Standby({
        id: 'productSelectorOverlay',
        target: 'productSelector',
        color: '#FFFFE0',
        centerIndicator: 'text',
        text: 'Loading...'
    });
    //document.body.appendChild(productSelectorOverlay.domNode);
    dojo.place(productSelectorOverlay.domNode, dojo.byId('productHidden'), 'after');
    productSelectorOverlay.startup();
}

/**
 * Initiates items for product group category selector.
 */
function initProductGroupCategorySelectorItems() {
    var deferred = new dojo.Deferred();

    // add division items to product group category selector store
    var productGroupCategorySelector = dijit.byId('productGroupCategorySelector');
    var productGroupSelector = dijit.byId('productGroupSelector');

    productGroupSelector.store.fetch({
        query: {'owner-type': 'division'},
        onComplete: function(items, request) {
            var divisions = [];
            var divisionMap = {};
            dojo.forEach(items, function(item) {
                var store = productGroupSelector.store;

                var divisionMoniker = store.getValue(item, 'owner-moniker') || null;
                var divisionName = store.getValue(item, 'owner-name') || null;
                if (divisionMoniker && !(divisionMoniker in divisionMap)) {
                    divisionMap[divisionMoniker] = divisionName;
                    divisions.push(divisionMoniker);
                }
            });

            dojo.forEach(divisions, function(divisionMoniker) {
                var store = productGroupCategorySelector.store;

                var divisionName = divisionMap[divisionMoniker];
                var divisionItem = {};
                divisionItem.moniker = divisionMoniker;
                divisionItem.name = 'All ' + divisionName;
                divisionItem.value = divisionMoniker;
                divisionItem.show = true;

                store.newItem(divisionItem);
            });

            productGroupCategorySelector.store.save();

            // signal callback
            deferred.callback();
        },
        onError: function(err) {
            console.error(err);
            deferred.errback(err);
        }
    });

    return deferred;
}

/**
 * Initiates widgets for product group navigation.
 */
function initProductGroupNavigation() {
    console.debug('[init]', 'product group navigation arrows');

    var productGroupSelector = dijit.byId("productGroupSelector");
    var productGroupStore = productGroupSelector.store;

    // init tree for product group navigation tooltip
    var queryTreeRoot = {};
    var identifier = GlobalVariables['identifier'];
    queryTreeRoot[identifier] = '$root$';

    var childTreeModel = new dijit.tree.TreeStoreModel({
        store: productGroupStore,
        query: queryTreeRoot,
        childrenAttrs: ['children'],
        deferItemLoadingUntilExpand: true
    });

    var parentTreeModel = new dijit.tree.TreeStoreModel({
        store: productGroupStore,
        query: queryTreeRoot,
        childrenAttrs: ['parents'],
        deferItemLoadingUntilExpand: true
    });

    // init tooltip tree
    var _nodes = null;

    var arrowDownButton = dijit.byId('arrowDownButton');
    var arrowDownTooltip = arrowDownButton.dropDown;
    var arrowDownTooltipNode = arrowDownTooltip.domNode;
    _nodes = dojo.query('div[class="childTree"]', arrowDownTooltipNode);
    var childTreeNode = _nodes[0];

    var childTree = new dijit.Tree({
        id: 'childTree',
        model: childTreeModel,
        showRoot: false,
        persist: false,
        getIconClass: getProductGroupIconClass,
        onDblClick: function(item, node, evt) {
            onDblClickTooltipTree.apply(this, arguments);
            arrowDownButton.closeDropDown();
        },
        // override "enter" key handler
        _onEnterKey: function(/*Object*/ message, /*Event*/ evt) {
            this._publish('execute', {item: message.item, node: message.node});
            this.onDblClick(message.item, message.node, evt);
        }
    }, childTreeNode);

    var arrowUpButton = dijit.byId('arrowUpButton');
    var arrowUpTooltip = arrowUpButton.dropDown;
    var arrowUpTooltipNode = arrowUpTooltip.domNode;
    _nodes = dojo.query('div[class="parentTree"]', arrowUpTooltipNode);
    var parentTreeNode = _nodes[0];

    var parentTree = new dijit.Tree({
        id: 'parentTree',
        model: parentTreeModel,
        showRoot: false,
        persist: false,
        getIconClass: getProductGroupIconClass,
        onDblClick: function(item, node, evt) {
            onDblClickTooltipTree.apply(this, arguments);
            arrowUpButton.closeDropDown();
        },
        // override "enter" key handler
        _onEnterKey: function(/*Object*/ message, /*Event*/ evt) {
            this._publish('execute', {item: message.item, node: message.node});
            this.onDblClick(message.item, message.node, evt);
        }
    }, parentTreeNode);
}

/**
 * onchange event handler for the "product group category" selector
 */
function onchangeProductGroupCategorySelector(value) {
    console.debug('[product group category]', value);

    var productGroupCategorySelector = dijit.byId('productGroupCategorySelector');
    var productGroupCategoryStore = productGroupCategorySelector.store;
    var categoryItem = productGroupCategorySelector.attr('item');
    if (!categoryItem) {
        return;
    }

    var category = productGroupCategoryStore.getValue(categoryItem, 'value');

    // update hidden form input field
    dojo.attr('productGroupCategoryHidden', 'value', category);

    // product group category is ready
    demo.selector.onReadyProductGroupCategorySelector();

    // update product group selector
    var productGroupSelector = dijit.byId('productGroupSelector');
    switch (category) {
    case 'all':
        updateProductGroupSelector();
        //resetProductGroupSelector(category);
        break;
    case 'dsp':
        updateProductGroupSelector();
        //productGroupSelector.reset();
        break;
    case 'fav':
        updateProductGroupSelector();
        //productGroupSelector.reset();
        break;
    default:
        updateProductGroupSelector();
    }

    // enable product group selector
    productGroupSelector.attr('disabled', false);
}

/**
 * onchange event handler for the "product group" selector
 */
function onchangeProductGroupSelector(value) {
    console.debug('[product group]', value);

    var productGroupSelector = dijit.byId('productGroupSelector');
    var store = productGroupSelector.store;

    var _onChangeProductGroupCallback = function(item) {
        // invalid item, reset to default value
        if (!item) {
            productGroupSelector.item = null;
            dojo.attr('productGroupHidden', 'value', 'clear');
            dijit.byId('arrowDownButton').attr('disabled', true);
            dijit.byId('arrowUpButton').attr('disabled', true);
            return;
        }

        // update hidden form input field
        productGroupSelector.attr('item', item);
        var identity = store.getIdentity(item);
        dojo.attr('productGroupHidden', 'value', identity);
    };

    // validation
    if (!productGroupSelector.isValid()) {
        _onChangeProductGroupCallback(null);
        return;
    }

    // TODO: update tree for arrow icons
    var _setArrowIcons = function(rootItem) {
        // reload child tree
        loadTreeItems(store, rootItem, "children", updateTooltipTree, {
            tooltipParentWidget: dijit.byId("arrowDownButton"),
            treeId: "childTree",
            store: store,
            rootItem: rootItem
        });

        // reload parent tree
        loadTreeItems(store, rootItem, "parents", updateTooltipTree, {
            tooltipParentWidget: dijit.byId("arrowUpButton"),
            treeId: "parentTree",
            store: store,
            rootItem: rootItem
        });
    };

    store.fetch({
        query: {name: value},
        onComplete: function(items) {
            if (!items || !items.length || items.length < 1) {
                _onChangeProductGroupCallback(null);

                // product group is ready
                demo.selector.onReadyProductGroupSelector(dojo.attr('productGroupHidden', 'value'));
                return;
            }

            var filteredItems = dojo.filter(items, function(item) {
                var type = store.getValue(item, 'type');
                return type === 'productgroup';
            });

            var item = null;
            if (filteredItems.length > 0) {
                item = filteredItems[0];
            }

            if (!item) {
                _onChangeProductGroupCallback(null);

                // product group is ready
                demo.selector.onReadyProductGroupSelector(dojo.attr('productGroupHidden', 'value'));
                return;
            }

            _onChangeProductGroupCallback(item);

            // product group is ready
            demo.selector.onReadyProductGroupSelector(dojo.attr('productGroupHidden', 'value'));

            /* ===== other callbacks ===== */
            // update product selector
            updateProductSelector();

            // update tree for arrow icons
            _setArrowIcons(item);
        }
    });

    // TODO: update tree for arrow icons
}

/**
 * onchange event handler for the "product" selector
 */
function onchangeProductSelector(value) {
    console.debug('[product]', value);

    var productSelector = dijit.byId('productSelector');
    var store = productSelector.store;

    var _onChangeProductCallback = function(item) {
        // invalid item, reset to default value
        if (!item) {
            productSelector.item = null;
            dojo.attr("productHidden", "value", "clear");
            return;
        }

        // update hidden form input field
        productSelector.attr("item", item);
        var identity = store.getIdentity(item);
        dojo.attr("productHidden", "value", identity);
    };

    // validation
    if (!productSelector.isValid()) {
        _onChangeProductCallback(null);
        return;
    }

    store.fetch({
        query: {name: value, type: 'product'},
        onComplete: function(items) {
            if (!items || !items.length || items.length < 1) {
                _onChangeProductCallback(null);
                return;
            }

            var filteredItems = dojo.filter(items, function(item) {
                var type = store.getValue(item, 'type');
                return type === 'product';
            });

            var item = null;
            if (filteredItems.length > 0) {
                item = filteredItems[0];
            }

            if (!item) {
                _onChangeProductCallback(null);
                return;
            }

            // update
            _onChangeProductCallback(item);

            // product is ready
            demo.selector.onReadyProductSelector(dojo.attr('productHidden', 'value'));
        }
    });
}

/**
 * Show loading overlay for the "product group category" selector.
 */
function showProductGroupCategorySelectorOverlay() {
    // show loading overlay for product group category selector
    var productGroupCategorySelectorOverlay = dijit.byId('productGroupCategorySelectorOverlay');
    productGroupCategorySelectorOverlay.show();
}

/**
 * Hide loading overlay for the "product group category" selector.
 */
function hideProductGroupCategorySelectorOverlay() {
    // hide loading overlay for product group category selector
    var productGroupCategorySelectorOverlay = dijit.byId('productGroupCategorySelectorOverlay');
    productGroupCategorySelectorOverlay.hide();
}

/**
 * Show loading overlay for the "product group" selector.
 */
function showProductGroupSelectorOverlay() {
    dijit.byId('productGroupSelector').attr('disabled', true);

    // show loading overlay for product group selector
    var productGroupSelectorOverlay = dijit.byId('productGroupSelectorOverlay');
    productGroupSelectorOverlay.show();
}

/**
 * Hide loading overlay for the "product group" selector.
 */
function hideProductGroupSelectorOverlay() {
    dijit.byId('productGroupSelector').attr('disabled', false);

    // hide loading overlay for product group selector
    var productGroupSelectorOverlay = dijit.byId('productGroupSelectorOverlay');
    productGroupSelectorOverlay.hide();
}

/**
 * Show loading overlay for the "product" selector.
 */
function showProductSelectorOverlay() {
    dijit.byId('productSelector').attr('disabled', true);

    // show loading overlay for product selector
    var productSelectorOverlay = dijit.byId("productSelectorOverlay");
    productSelectorOverlay.show();
};

/**
 * Hide loading overlay for the "product" selector.
 */
function hideProductSelectorOverlay() {
    dijit.byId('productSelector').attr('disabled', false);

    // hide loading overlay for product selector
    var productSelectorOverlay = dijit.byId('productSelectorOverlay');
    productSelectorOverlay.hide();
}

////////////////////////////////////////////////////////////////////////////////
demo.selector.publish = function(widgetId, topic, data) {
    if (widgetId) {
        var channel = widgetId + "-" + topic;
        var args = [];
        if (arguments.length > 2) {
            for (var i = 2; i < arguments.length; i++) {
                var arg = arguments[i];
                args.push(arg);
            }
        }
        dojo.publish(channel, args);
    }
};

demo.selector.onFirstReadyProductGroupCategorySelector = function(value) {
    console.info("ProductGroupCategorySelector", "first ready");
    demo.selector.publish("productGroupCategorySelector", "first-ready", value);

    // TODO: can be add to page notifier now
    demo.selector.addToPageNotifier("productGroupCategorySelector");
};

demo.selector.onFirstReadyProductGroupSelector = function(value) {
    console.info("ProductGroupSelector", "first ready");
    demo.selector.publish("productGroupSelector", "first-ready", value);

    // TODO: can be add to page notifier now
    demo.selector.addToPageNotifier("productGroupSelector");
};

demo.selector.onFirstReadyProductSelector = function(value) {
    console.info("ProductSelector", "first ready");
    demo.selector.publish("productSelector", "first-ready", value);

    // TODO: can be add to page notifier now
    demo.selector.addToPageNotifier("productSelector");
};

demo.selector.onReadyProductGroupCategorySelector = function(value) {
    var settings = demo.selector.settings["productGroupCategorySelector"];

    // first ready
    if (settings.ready === false)
        demo.selector.onFirstReadyProductGroupCategorySelector();

    settings.ready = true;
    console.info("ProductGroupCategorySelector", "ready");
    demo.selector.publish("productGroupCategorySelector", "ready", value);
};

demo.selector.onReadyProductGroupSelector = function(value) {
    var settings = demo.selector.settings["productGroupSelector"];

    // first ready
    if (settings.ready === false)
        demo.selector.onFirstReadyProductGroupSelector();

    settings.ready = true;
    console.info("ProductGroupSelector", "ready");
    demo.selector.publish("productGroupSelector", "ready", value);
};

demo.selector.onReadyProductSelector = function(value) {
    var settings = demo.selector.settings["productSelector"];

    // first ready
    if (settings.ready === false)
        demo.selector.onFirstReadyProductSelector();

    settings.ready = true;
    console.info("ProductSelector", "ready");
    demo.selector.publish("productSelector", "ready", value);
};

/**
 * Add widget to page notifier.
 *
 * @param {String} widgetId
 *          The id of the widget.
 */
demo.selector.addToPageNotifier = function(widgetId) {
    if (demo.selector.includedInPageNotifier[widgetId] !== true) {
        dojo.connect(dijit.byId(widgetId), "onChange", function() {
            debug(widgetId, "has been changed");
        });
        demo.selector.includedInPageNotifier[widgetId] = true;
    }
};

function getProductGroupIconClass(item, opened) {
    var iconClass = (!item || this.model.mayHaveChildren(item)) ? (opened ? "FolderOpenedIcon" : "FolderClosedIcon") : "FolderClosedIcon";
    //console.info(iconClass);
    return iconClass;
}

/***********************************
 * Validation
 *
 * validate(isFocused) -> isValid(isFocused) -> validator(value, constraints)
 * validateHandler()
 *
 ***********************************/
function initValidation(widget, valueFieldNode) {
    return;
    widget.validator = validator;

    var _validateHandler = function(widget, callback) {
        if (widget.isValid) {
            if (!widget.isValid() && !widget.attr("disabled")) {
                callback(widget, false);
            } else {
                callback(widget, true);
            }
        }
    };

    var _callback = function(widget, isValid) {
        if (isValid === false) {
            var node = dojo.byId(valueFieldNode);
            dojo.attr(node, "value", "clear");
        } else if (isValid === true) {
            //widget.onChange(widget.value);
        }
    };

    //dojo.connect(widget, "validate", dojo.hitch(null, _validateHandler, widget, _callback));
}

function validator(value, constraints) {
    if (this._focused) {
        return true;
    }

    if (!value) {
        return false;
    }

    var store = this.store;
    var item = this.attr("item"); // selected item

    if (!item) {
        return false;
    }

    // compare name
    var name = store.getValue(item, "name");
    if (value !== name) {
        return false;
    }

    // compare type
    var type = store.getValue(item, "type");
    if (type == "owner") {
        return false;
    }

    return true;
}

////////////////////////////////////////////////////////////////////////////////
function updateProductGroupCategorySelector(callback) {
    updateProductGroupCategoryItems(["fav", "dsp"], callback);
}

function updateProductGroupCategoryItems(identities, callback) {
    var identity = identities.shift();
    if (!identity) {
        if (callback) {
            callback.call(null);
        }
        return;
    }

    var productGroupSelector = dijit.byId("productGroupSelector");
    var productGroupCategorySelector = dijit.byId("productGroupCategorySelector");

    var query = {};
    query[identity] = true;

    // check if exists items in productGroupStore
    var productGroupStore = productGroupSelector.store;
    productGroupStore.fetch({
        query: query,
        onComplete: function(items, request) {
            var count = items.length;
            console.debug(identity, count);
            var isShow = count > 0 ? true : false;

            var productGroupCategoryStore = productGroupCategorySelector.store;
            productGroupCategoryStore.fetchItemByIdentity({
                identity: identity,
                onItem: function(item) {
                    // set attribute show=true
                    productGroupCategoryStore.setValue(item, "show", isShow);
                    productGroupCategoryStore.save();

                    // recursive
                    updateProductGroupCategoryItems(identities, callback);
                },
                onError: function() {
                    console.warn("cannot find productGroupSelector item");
                }
            });
        }
    });
}


function setProductGroupCategorySelector(category) {
    var _setProductGroupCategorySelector = function() {
        var productGroupCategorySelector = dijit.byId("productGroupCategorySelector");
        var productGroupCategoryStore = productGroupCategorySelector.store;
        productGroupCategoryStore.fetchItemByIdentity({
            identity: category,
            onItem: function(item){
                productGroupCategorySelector.attr("item", item);
            },
            onError: function(){
                console.warn("cannot find productGroupCategorySelector item");
            }
        });
    };

    updateProductGroupCategorySelector(_setProductGroupCategorySelector);
}

function resetProductGroupCategorySelector() {
    // select default product group
    var productGroupSelector = dijit.byId('productGroupSelector');
    var defaultGroup = GlobalVariables.DefaultOptions['productGroup'];
    if (defaultGroup) {
        productGroupSelector.attr('identity', defaultGroup);
    }

    // hide loading overlay for product group selector
    hideProductGroupSelectorOverlay();

    // hide loading overlay for product group category selector
    hideProductGroupCategorySelectorOverlay();

    // select default product group category
    var productGroupCategorySelector = dijit.byId('productGroupCategorySelector');
    var productGroupCategoryStore = productGroupCategorySelector.store;

    var defaultCategory = GlobalVariables.DefaultOptions['productGroupCategory'];
    if (defaultCategory) {
        // enable default category
        productGroupCategoryStore.fetchItemByIdentity({
            identity: defaultCategory,
            onItem: function(item) {
                // set attribute show=true
                productGroupCategoryStore.setValue(item, 'show', true);
                productGroupCategoryStore.save();

                // select default category
                productGroupCategorySelector.attr('item', item);
            },
            onError: function(error) {
                console.error(error);
            }
        });

        return;
    }

    productGroupCategoryStore.fetch({
        query: {show: true},
        onComplete: function(items, request) {
            // select category by rules
            var showItemsMap = {};
            dojo.forEach(items, function(item) {
                var identity = productGroupCategoryStore.getIdentity(item);
                showItemsMap[identity] = item;
            });

            var selectedItem = null;

            // select "fav" category if exists
            if (showItemsMap['fav']) {
                selectedItem =  showItemsMap['fav'];
                productGroupCategorySelector.attr('item', selectedItem);
                return;
            }

            // select "dsp" category if exists
            if (showItemsMap['dsp']) {
                selectedItem = showItemsMap['dsp'];
                productGroupCategorySelector.attr('item', selectedItem);
                return;
            }

            // select first category
            selectedItem = items[0];
            productGroupCategorySelector.attr('item', selectedItem);
        },
        onError: function(error) {
            console.error(error);
        }
    });
}

////////////////////////////////////////////////////////////////////////////////
function updateProductGroupSelector() {
    var productGroupCategorySelector = dijit.byId('productGroupCategorySelector');
    var productGroupCategoryStore = productGroupCategorySelector.store;
    var categoryItem = productGroupCategorySelector.attr('item');
    var category = productGroupCategoryStore.getValue(categoryItem, 'value');

    var query = null;
    switch (category) {
    case 'all':
    case 'dsp':
    case 'fav':
        query = GlobalVariables.TreeSelectorQueries[category];
        break;
    default:
        query = {'owner-moniker': category};
    }

    // Since the store held by the "product group" selector has all the data of "favorites" and "starting points",
    // we just need to update the "query" attribute to get a different tree view of product groups.
    if (query) {
        var productGroupSelector = dijit.byId('productGroupSelector');
        productGroupSelector.attr('query', query);
    }
}

function resetProductGroupSelector(category) {

    // skip if category=all.
    if (category === "all") {
        return;
    }

    var query = {};
    query[category] = true;

    // check items in productGroupStore
    var productGroupSelector = dijit.byId("productGroupSelector");
    var productGroupStore = productGroupSelector.store;
    var selectedItem = productGroupSelector.attr("item");
    if (!selectedItem) {
        return;
    }
    var selectedIdentity = productGroupStore.getIdentity(selectedItem);

    productGroupStore.fetch({
        query: query,
        onComplete: function(items, request) {
            var found = false;
            var identity = null;
            for(var i in items) {
                var item = items[i];
                identity = productGroupStore.getIdentity(item);
                if (identity === selectedIdentity) {
                    found = true;
                    break;
                }
            }

            // if not found item, reset productGroupSelector
            if (found === false) {
                productGroupSelector.reset();
            }
        }
    });
}

////////////////////////////////////////////////////////////////////////////////
function updateProductSelector() {
    var productGroupSelector = dijit.byId('productGroupSelector');
    var productGroupStore = productGroupSelector.store;
    var groupItem = productGroupSelector.attr('item');
    if (!groupItem) {
        return;
    }

    var groupId = productGroupStore.getIdentity(groupItem);
    var groupName = productGroupStore.getValue(groupItem, 'name');

    if (groupName) {
        var productSelector = dijit.byId('productSelector');
        productSelector.reset();

        // now get product list from server
        var url = GlobalVariables.dataPath + '/product_groups.json';
        dojo.xhrGet({
            url: url,
            content: {group: groupId},
            handleAs: 'json',
            load: function(json) {
                // hide loading
                hideProductSelectorOverlay();

                var productStoreData = getProductData(groupName);
                demo.selector.publish("productSelector", "data-loaded", productStoreData);
            },
            error: function(response, ioargs) {
                // hide loading
                hideProductSelectorOverlay();

                console.error('Error occured:', response);
                var status = ioargs.xhr.status;
                if (status === 403) {
                    // May want to display some form of deleted references error message here, or may not.
                } else {
                    // May want to display some form of general error message here, or may not.
                }
            }
        });

        // show loading
        showProductSelectorOverlay();
    }
}

////////////////////////////////////////////////////////////////////////////////
function destroyTree(tree) {
    tree.destroy();
}

function createTree(id, containerNode, treeModel, params) {
    var tree = dijit.byId(id);
    if (tree) {
        destroyTree(tree);
    }

    var showRoot = true;
    if (treeModel.isInstanceOf(dijit.tree.ForestStoreModel)) {
        showRoot = false;
    }

    var treeParams = {
        id: id,
        model: treeModel,
        showRoot: showRoot,
        persist: false
    };

    dojo.mixin(treeParams, params);

    tree = new dijit.Tree(treeParams);
    containerNode.appendChild(tree.domNode);
    tree.startup();
}

function changeModel(tree, container, treeModel, showRoot) {
    var id = tree.id;
    tree.destroy();

    tree = new dijit.Tree({
        id: id,
        model: treeModel,
        showRoot: showRoot,
        persist: false
    });
    container.appendChild(tree.domNode);
    tree.startup();
}

function callbackParentItems(item, parentItems) {
    callbackResultItems(item, parentItems, "parent");
}

function callbackChildItems(item, childItems) {
    callbackResultItems(item, childItems, "child");
}

function callbackResultItems(item, resultItems, type) {
    var selector = dijit.byId("productGroupSelector");
    var store = selector.store;

    var ids = [];
    dojo.forEach(resultItems, function(resultItem) {
        var id = store.getIdentity(resultItem);
        ids.push(id);
    });
    var pattern = ids.join("|");
    var regExp = new RegExp(pattern, "mi");
    var query = {
        id: pattern
    };
    var itemId = store.getIdentity(item);
    append("item:", itemId, "=>", type + ":", regExp.source);
}

function onDblClickTooltipTree(/* dojo.data */ item, /*TreeNode*/ node, /*Event*/ evt) {
    var selector = dijit.byId("productGroupSelector");
    selector.attr("item", item);
}

////////////////////////////////////////////////////////////////////////////////
// Click parent icon.
function showParentSelectorTooltip(node) {
    var tooltip = dijit.byId("parentSelectorTooltip");
    showSelectorTooltip(tooltip, node);
}

// Click child icon.
function showChildSelectorTooltip(node) {
    var tooltip = dijit.byId("childSelectorTooltip");
    showSelectorTooltip(tooltip, node);
}

function showSelectorTooltip(tooltip, aroundNode) {
    dijit.popup.open({
        //parent: parentWidget,
        popup: tooltip,
        around: aroundNode,
        onExecute: function(){
            closeTooltip(tooltip);
        },
        onCancel: function(){
            closeTooltip(tooltip);
        },
        onClose: function(){
            console.debug("onClose")
        }
    });
}

function closeTooltip(tooltip) {
    dijit.popup.close(tooltip);
}

// Click OK in select parent tooltip dialog.
function focusParent() {
    var parentTree = dijit.byId("parentTree");
    setProductGroupFromPopupTree(parentTree);

    // set productGroupCategorySelector to "all"
    //setProductGroupCategorySelector("all");
}

// Click OK in select child tooltip dialog.
function focusChild() {
    var childTree = dijit.byId("childTree");
    setProductGroupFromPopupTree(childTree);

    // set productGroupCategorySelector to "all"
    //setProductGroupCategorySelector("all");
}

function setProductGroupFromPopupTree(tree) {
    var selector = dijit.byId("productGroupSelector");

    var item = tree.attr("selectedItem");
    var name = tree.model.store.getValue(item, "name");
    debug("selected item:", name);

    selector.attr("item", item);
}

function loadTreeItems(store, item, attributeName, callback, callbackArgs) {
    var results = [];
    callbackArgs.subItems = results;

    if (!item) {
        callback.call(null, callbackArgs);
        return;
    }

    var resultItems = store.getValues(item, attributeName);
    if (resultItems.length < 1) {
        callback.call(null, callbackArgs);
    }

    for (var i = 0; i < resultItems.length; i+=1) {
        var resultItem = resultItems[i];

        if(!store.isItemLoaded(resultItem)){
            store.loadItem({
                item: resultItem,
                onItem: function(loadedItem) {
                    results.push(loadedItem);
                    if (i === resultItems.length - 1) {
                        callback.call(null, callbackArgs);
                    }
                },
                onError: function() {
                    console.warn("error loading parent item");
                }
            });
        } else {
            results.push(resultItem);
            if (i === resultItems.length - 1) {
                callback.call(null, callbackArgs);
            }
        }
    }
}

function updateTooltipTree(args) {

    var treeId = args.treeId;
    var store = args.store;
    var rootItem = args.rootItem;
    var subItems = args.subItems;
    var tooltipParentWidget = args.tooltipParentWidget;
    var tooltip = tooltipParentWidget.dropDown;

    callbackParentItems.call(null, rootItem, subItems);

    if (subItems.length < 1) {
        tooltipParentWidget.attr("disabled", true);
        return;
    }

    tooltipParentWidget.attr("disabled", false);

    var queryTreeRoot = {};
    var identifier = GlobalVariables["identifier"];
    var rootIdentity = store.getIdentity(rootItem);
    queryTreeRoot[identifier] = rootIdentity;

    var tree = dijit.byId(treeId);
    tree.model.query = queryTreeRoot;
    tree.model.root = null;

    // re-create tooltip tree
    var treeContainerNode = tree.domNode.parentNode;
    createTree(treeId, treeContainerNode, tree.model, {
        getIconClass: getProductGroupIconClass,
        onDblClick: function(item, node, evt) {
            onDblClickTooltipTree.apply(this, arguments);
            tooltipParentWidget.closeDropDown();
        },
        _onEnterKey: function(/*Object*/ message, /*Event*/ evt) {
            this._publish("execute", { item: message.item, node: message.node } );
            this.onDblClick(message.item, message.node, evt);
        }
    });
}

demo.selector.changeStoreForSelector = function(selector, store) {
    if (selector) {
        var identity = null;
        var selectedItem = selector.attr("item");
        if (selectedItem) {
            identity = selector.store.getIdentity(selectedItem);
        }
        selector.attr("store", store); // update store
        selector.attr("identity", identity); // restore selected item
        selector.attr("disabled", false);
    }
};

// click change store button
function changeStore(url) {
    var productGroupSelector = dijit.byId("productGroupSelector");
    var store = new dojo.data.ItemFileWriteStore({url: url});
    store.fetch({
        onComplete: function(items) {
            demo.selector.changeStoreForSelector(productGroupSelector, store);
        }
    });
}

// click focus node button
function focusNode(path) {
    var selector = dijit.byId("productGroupSelector");

    if (!dojo.isArray(path)) {
        path = [].push(path);
    }

    var length = path.length;
    var identity = path[length-1];

    var item = selector.store._getItemByIdentity(identity);
    if (item) {
        selector.attr("item", item);
    }
}

// click add to favorites link
function addToFavorites() {
    // first we find the current option and its value
    var productGroupSelector = dijit.byId("productGroupSelector");
    var productGroupStore = productGroupSelector.store;
    var item = productGroupSelector.attr("item");
    if (!item) {
        return;
    }

    // in the exceptional case that the "new favorite" is already here, we stop.
    var fav = productGroupStore.getValue(item, "fav", false);
    if (fav === true) {
        debug("Selected product group has already been saved as a favorite.");
        return;
    }

    var _getPutData = function(favorites) {
        var identifier = GlobalVariables["identifier"];
        var favItems = [];

        dojo.forEach(favorites, function(identity) {
            var favItem = {};
            favItem[identifier] = identity;
            favItems.push(favItem);
        });

        var putData = {"nested-productgroups":favItems};
        return putData;
    };

    var _updateFavoritesInServer = function (putData, callback) {
        // now we convert the new favorites to JSON format to be sent to the server.
        var putDataJsonStr = dojo.toJson(putData);

        // now we update favorite data in server side
        var url = GlobalVariables.dataPath + "/product_groups.json";
        dojo.xhrPut({
            url: url,
            contentType: "application/json",
            putData: putDataJsonStr,
            handle: callback,
            error: function(error) {
                console.warn("Error occured:", error);
                debug("Error occured:", error);
            }
        });
    };

    var _updateFavoritesInClient = function() {
        // now we update favorite data in client side
        productGroupStore.setValue(item, "fav", true);
        productGroupStore.save({
            onComplete: function() {
                // update product group category selector to enable "favorites" option
                updateProductGroupCategorySelector();

                // update product group selector if current category=fav
                var productGroupCategorySelector = dijit.byId("productGroupCategorySelector");
                var productGroupCategoryStore = productGroupCategorySelector.store;
                var categoryItem = productGroupCategorySelector.attr("item");
                if (categoryItem) {
                    var category = productGroupCategoryStore.getValue(categoryItem, "value");
                    if (category === "fav") {
                        // refresh tree view if current category=fav
                        updateProductGroupSelector();
                    }
                }

                // disable "add to favorites" link
                dijit.byId("addToFavoritesLink").attr("disabled", true);

                // show successful message
                debug("Selected product group has been saved as a favorite.");
            },
            onError: function(error) {
                console.warn(error);
            }
        });
    };

    var newFavorite = productGroupStore.getIdentity(item);

    // fetch favorites in the data store
    productGroupStore.fetch({
        query: {fav: true},
        onComplete: function(items) {
            var favorites = [];
            dojo.forEach(items, function(item) {
                var identity = productGroupStore.getIdentity(item);
                favorites.push(identity);
            });
            console.debug("favorites", favorites);
            favorites.push(newFavorite);

            var putData = _getPutData(favorites);
            _updateFavoritesInServer(putData, _updateFavoritesInClient);
        }
    });
}

// check and update "add to favorites" link status
function updateAddToFavoritesStatus() {
    // first we check the current category option
    var productGroupCategorySelector = dijit.byId("productGroupCategorySelector");
    var productGroupCategoryStore = productGroupCategorySelector.store;
    var categoryItem = productGroupCategorySelector.attr("item");
    if (categoryItem) {
        var category = productGroupCategoryStore.getValue(categoryItem, "value");
        if (category === "fav") {
            dijit.byId("addToFavoritesLink").attr("disabled", true);
            return;
        }
    }

    // then we check the current group option
    var productGroupSelector = dijit.byId("productGroupSelector");
    var store = productGroupSelector.store;
    var item = productGroupSelector.attr("item");
    if (!store.isItem(item)) {
        dijit.byId("addToFavoritesLink").attr("disabled", true);
        return;
    }

    var isFavorited = store.getValue(item, "fav", false);
    dijit.byId("addToFavoritesLink").attr("disabled", (isFavorited === true));
}

function getProductData(groupName) {
    var identifier = GlobalVariables["identifier"];
    var data = {
        identifier: identifier,
        label: "name",
        items: []
    };

    var groupItem = {};
    groupItem[identifier] = "group";
    groupItem.name = groupName;
    groupItem.type = "owner";
    groupItem.search = false;
    groupItem.top = true;
    groupItem.children = [];
    data.items.push(groupItem);

    var item = null;
    for (var i = 1; i <= 10; i++) {
        item = {};
        item[identifier] = "product_" + i;
        item.name = groupName + " v" + i;
        item.type = "product";
        item.search = true;

        var itemRef = {_reference: item[identifier]};
        groupItem.children.push(itemRef);

        data.items.push(item);
    }

    return data;
}

function getSelectorValue(id) {
    var selector = dijit.byId(id);
    if (!selector) {
        debug("selector", id, "not found!");
    }

    var value = selector.attr("value");
    var item = selector.attr("item");
    console.debug(id, "->", value, item);
    debug(id, "->", value, ",", (item && item.id) ? item.id : "null");
}

function setIdentity(id, identity) {
    var selector = dijit.byId(id);
    if (!selector) {
        debug("selector", id, "not found!");
    }

    selector.attr("identity", identity);
}
</script>
</head>
<body class="tundra">

  <h2 id="version">Unknown Version</h2>

  <div id="main" class="container">

    <div id="titlePanel" dojoType="dijit.TitlePane" title="Panel" style="">
      <div id="resizablePanel" style="position:relative; padding: 10px; border:1px solid black;">

        <!-- Content -->
        <div class="content">
          <form id="form1" name="__form" action="" method="get">
            <table>
              <tbody>
                <!-- product group category -->
                <tr>
                  <td><label for="productGroupCategorySelector">Product group category:</label></td>
                  <td>
                    <input id="productGroupCategorySelector" type="text" style="width: 200px" />
                    <input id="productGroupCategoryHidden" type="text" name="set:$page.productGroupCategory" value="" />
                  </td>
                </tr>
                <!-- product group -->
                <tr>
                  <td><label for="productGroupSelector">Product group:</label></td>
                  <td>
                    <input id="productGroupSelector" type="text" style="width: 200px" />
                    <input id="productGroupHidden" type="text" name="set:$page.productGroup" value="" onchange="console.info('change');" />

                    <!-- ArrowDown DropDownButton -->
                    <div id="arrowDownButton" dojoType="dijit.form.DropDownButton" iconClass="iconArrowDown" showLabel="false" autoWidth="false" disabled="disabled">
                      <span>⬇⬇</span>
                      <div id="childSelectorTooltip" dojoType="dijit.TooltipDialog">
                        <div><strong>Select a child item</strong></div>
                        <!-- Tree -->
                        <div class="TreeSelectorPopUp">
                          <div class="childTree"></div>
                        </div>
                        <button id="selectChildButton" dojoType="dijit.form.Button" type="submit" onclick="focusChild();">Select</button>
                      </div>
                    </div>

                    <!-- ArrowUp DropDownButton -->
                    <div id="arrowUpButton" dojoType="dijit.form.DropDownButton" iconClass="iconArrowUp" showLabel="false" autoWidth="false" disabled="disabled">
                      <span>⬆⬆</span>
                      <div id="parentSelectorTooltip" dojoType="dijit.TooltipDialog">
                        <div><strong>Select a parent item</strong></div>
                        <!-- Tree -->
                        <div class="TreeSelectorPopUp">
                          <div class="parentTree"></div>
                        </div>
                        <button id="selectParentButton" dojoType="dijit.form.Button" type="submit" onclick="focusParent();">Select</button>
                      </div>
                    </div>

                    <br />
                    <button id="addToFavoritesLink" dojoType="dijit.form.Button" baseClass="linkButton" iconClass="addFavIcon" disabled="disabled" onClick="addToFavorites();">Add to favorites</button>
                  </td>
                </tr>
                <!-- product -->
                <tr>
                  <td><label for="productSelector">Product:</label></td>
                  <td>
                    <input id="productSelector" type="text" style="width: 200px" />
                    <input id="productHidden" type="text" name="set:$page.product" value="" />
                  </td>
                </tr>
                <tr>
                  <td>
                    <input type="submit" name="ignore:" value="Refresh" id="refreshButton" />
                  </td>
                  <td></td>
                </tr>
              </tbody>
            </table>
          </form>
        </div>

        <!-- Resize Handle -->
        <div id="resizeHandle" dojoType="dojox.layout.ResizeHandle" targetId="resizablePanel"></div>
      </div>
    </div>

    <!-- Button Panel -->
    <div dojoType="dojo.dnd.Moveable">
      <div id="buttonPanel" dojoType="dijit.TitlePane" title="Button Panel" style="">
        <!-- Button -->
        <button id="showValueButton" dojoType="dijit.form.Button" onClick="getSelectorValue('productGroupSelector');">Show value of product group</button>
        <button id="setIdentityButton" dojoType="dijit.form.Button" onClick="setIdentity('productGroupSelector', 'AIM');">Set identity of product group</button>
        <button dojoType="dijit.form.Button" onClick="changeStore(GlobalVariables.dataPath + '/productgroups/$user-division-designated-products.json');">Change store: Division starting points</button>
        <button dojoType="dijit.form.Button" onClick="changeStore(GlobalVariables.dataPath + '/productgroups/$user-designated-products.json');">Change store: My favorites</button>
        <button dojoType="dijit.form.Button" onClick="focusNode(['$root$', 'Iterable', 'Collection', 'List']);">focus List</button>
        <button dojoType="dijit.form.Button" onClick="focusNode(['$root$', 'Map', 'SortedMap', 'NavigableMap', 'TreeMap']);">focus TreeMap</button>
        <button dojoType="dijit.form.Button" onClick="focusNode(['$root$', 'Map', 'AbstractMap', 'HashMap', 'JSONObject']);">focus JSONObject</button>
        <button dojoType="dijit.form.Button" onClick="focusNode(['$root$', 'Iterable', 'Collection', 'List', 'AbstractList', 'ArrayList', 'JSONArray']);">focus JSONArray</button>

        <a id="up_arrow" href="javascript://" onclick="showParentSelectorTooltip(this);" title="select a parent" style="display: inline;">⬆⬆</a>
        <a id="down_arrow" href="javascript://" onclick="showChildSelectorTooltip(this);" title="select a child" style="display: inline;">⬇⬇</a>
    </div>
  </div>

  <!-- Debug Panel -->
  <div id="debugPanel" dojoType="dojox.layout.FloatingPane" title="Console" resizable="true" dockable="true" style="position: absolute; bottom: 20px; right: 20px; width: 500px; height: 150px;">
    <pre id="debugPanelContent"></pre>
  </div>
</body>
</html>
